package com.liao.tensquare.admin.controller;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.liao.tensquare.annotation.Log;
import com.liao.tensquare.annotation.PreAuthorize;
import com.liao.tensquare.constants.TokenConstants;
import com.liao.tensquare.entity.Result;
import com.liao.tensquare.entity.StatusCode;
import com.liao.tensquare.enums.OperatorType;
import com.liao.tensquare.exception.UserInvalidException;
import com.liao.tensquare.admin.pojo.TbUser;
import com.liao.tensquare.admin.service.TbUserService;
import com.liao.tensquare.admin.service.TokenService;
import com.liao.tensquare.utils.IdWorker;
import com.liao.tensquare.utils.RedisConstant;
import com.liao.tensquare.utils.StringHelper;
import com.liao.tensquare.admin.vo.UserInfoResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping(value = "auth")
public class AuthController {

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private TbUserService tbUserService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private DefaultKaptcha defaultKaptcha;
    @Autowired
    private IdWorker idWorker;

    @Log(value = "获取验证码")
    @RequestMapping(value = "/captcha", method = RequestMethod.POST)
    public Result getCaptcha() throws IOException {
        String capText = defaultKaptcha.createText();
        BufferedImage capImg = defaultKaptcha.createImage(capText);
        //用于区别是哪个不同用户的验证码
        long uuid = idWorker.nextId();
        //使用:分隔会是存储结构分层
        redisTemplate.opsForValue().set(RedisConstant.REDIS_LOGIN_CAPTCHA_KEY + ":" + uuid,
                capText, RedisConstant.REDIS_USER_TOKEN_EXPIRED_TIME,TimeUnit.SECONDS);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ImageIO.write(capImg, "jpg", outputStream);
        Base64.Encoder encoder = Base64.getEncoder();
        HashMap<String, Object> map = new HashMap<>();
        map.put("captcha", encoder.encodeToString(outputStream.toByteArray()));
        map.put("capKey", String.valueOf(uuid));
        return new Result(true, "获取成功", StatusCode.OK, map);
    }

    @Log(value = "用户登录",isSave = true,operType = OperatorType.LOGIN)
    @RequestMapping(value = "/token", method = RequestMethod.POST)
    public Result login(@RequestBody Map<String, String> map) throws UserInvalidException {
        log.info("login...param->{}", map.toString());
        String code = map.get("code");
        String captchaKey = map.get("captchaKey");
        Result x = checkCaptcha(code, captchaKey);
        if (x != null) return x;
        Map<String, Object> login = tbUserService.login(map);
        return new Result(true, "登录成功", StatusCode.OK, login);
    }

    @RequestMapping(value = "/toLogin", method = RequestMethod.POST)
    public Result toLogin() {
        log.info("toLogin...");
        return new Result(false, "请先登录！", StatusCode.OK);
    }

    /**
     * 刷新Token
     */
    @Log(value = "刷新Token",isSave = true)
    @RequestMapping(value = "/token/refresh", method = RequestMethod.GET)
    public Result refresh(HttpServletRequest request) throws Exception {
        return new Result(true, "刷新成功", StatusCode.OK, tokenService.refresh(request));
    }

    /**
     * 更新用户信息
     *
     * @param tbUser
     * @return
     */
    @Log(value = "更新用户信息",isSave = true,operType = OperatorType.UPDATE)
    @PreAuthorize(hasPermission = "user:update")
    @RequestMapping(value = "/user/update", method = RequestMethod.POST)
    public Result updateUser(@RequestBody TbUser tbUser, HttpServletRequest request) {
        String userId = (String) request.getAttribute(TokenConstants.JWT_USER_ID);
        if (userId == null) {
            return new Result(false, "id不能为空", StatusCode.PARAMS_IN_ERROR);
        }
        tbUser.setId(userId);
        tbUserService.updateUser(tbUser);
        return new Result(true, "修改成功", StatusCode.OK);
    }

    @Log(value = "查询当前登录用户信息",isSave = true,operType = OperatorType.FIND)
    @RequestMapping(value = "/user/find", method = RequestMethod.GET)
    public Result findUser(HttpServletRequest request) {
        String userId = (String) request.getAttribute(TokenConstants.JWT_USER_ID);
        UserInfoResponse userInfo = tbUserService.findCurrentUserById(userId);
        return new Result(true, "查询成功", StatusCode.OK, userInfo);
    }

    @Log(value = "注销用户",isSave = true,operType = OperatorType.DELETE)
    @PreAuthorize(hasPermission = "user:del")
    @RequestMapping(value = "/user/del", method = RequestMethod.POST)
    public Result delUser(HttpServletRequest request) {
        String userId = (String) request.getAttribute(TokenConstants.JWT_USER_ID);
        if (userId == null) {
            return new Result(false, "用户Id不能为空", StatusCode.PARAMS_IN_ERROR);
        }
        return tbUserService.delUser(userId);
    }

    @Log(value = "登出",isSave = true)
    @RequestMapping(value = "/user/logout", method = RequestMethod.POST)
    public Result logout(HttpServletRequest request) throws Exception {
        tbUserService.logout((String) request.getAttribute(TokenConstants.JWT_USER_ID));
        return new Result(true, "退出成功", StatusCode.OK);
    }

    @Log(value = "修改密码",isSave = true,operType = OperatorType.UPDATE)
    @PreAuthorize(hasPermission = "user:updatePwd")
    @RequestMapping(value = "/user/updatePwd", method = RequestMethod.POST)
    public Result restPassword(HttpServletRequest request, @RequestBody Map<String, String> map) {
        String oldPwd = map.get("oldPwd");
        String newPwd = map.get("newPwd");
        String id = (String) request.getAttribute(TokenConstants.JWT_USER_ID);
        if (StringHelper.isEmpty(id)) {
            return new Result(false, "用户id不能为空", StatusCode.PARAMS_IN_ERROR);
        }
        if (StringHelper.isEmpty(newPwd)) {
            return new Result(false, "新密码不能为空", StatusCode.PARAMS_IN_ERROR);
        }
        return tbUserService.updatePassword(id, oldPwd, newPwd);
    }

    /**
     * 判断验证码是否过期
     *
     * @param code       验证码
     * @param captchaKey 验证码对应redis的键
     */
    private Result checkCaptcha(String code, String captchaKey) {
        if (StringHelper.isEmpty(captchaKey)) {
            return new Result(false, "captcha key is null", StatusCode.PARAMS_IN_ERROR);
        }
        String captchaValues = redisTemplate.opsForValue().get(RedisConstant.REDIS_LOGIN_CAPTCHA_KEY + ":" + captchaKey);
        if (null == code) {
            return new Result(false, "验证码为空", StatusCode.CAPTCHA_IS_NULL);
        }
        if (null == captchaValues || "".equals(captchaKey) || !captchaValues.equals(code.toLowerCase())) {
            return new Result(false, "验证码错误", StatusCode.CAPTCHA_EXPIRED);
        }
        return null;
    }
}
